package com.jade.journal.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.inject.Named;

import com.jade.framework.base.lang.ReflectUtils;
import com.jade.framework.base.util.DataUtils;
import com.jade.journal.AppenderFactory;
import com.jade.journal.JournalAppender;
import com.jade.journal.JournalFormat;
import com.jade.journal.appender.DailyFileAppender;
import com.jade.journal.appender.DatabaseAppender;
import com.jade.journal.appender.FileAppender;
import com.jade.journal.appender.MultiAppender;
import com.jade.journal.desc.AppenderDesc;
import com.jade.journal.desc.JournalDesc;
import com.jade.journal.format.GenericFormat;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;

/**
 * Appender工厂实现。
 *
 * @author sky
 * @version 1.0 14-9-22 下午5:55
 */
@Named ("system_journalAppenderFactory")
public class AppenderFactoryImpl implements AppenderFactory
{
    private Map<String, String> classMap;
    private Map<String, JournalFormat> formatMap;

    @PostConstruct
    public void init()
    {
        if (classMap == null) {
            classMap = new HashMap<String, String>();
        }
        if (!classMap.containsKey(DailyFileAppender.TYPE)) {
            classMap.put(DailyFileAppender.TYPE, DailyFileAppender.class.getName());
        }
        if (!classMap.containsKey(FileAppender.TYPE)) {
            classMap.put(FileAppender.TYPE, FileAppender.class.getName());
        }
        if (!classMap.containsKey(DatabaseAppender.TYPE)) {
            classMap.put(DatabaseAppender.TYPE, DatabaseAppender.class.getName());
        }
        if (formatMap == null) {
            formatMap = new HashMap<String, JournalFormat>();
        }
        if (!formatMap.containsKey("default")) {
            formatMap.put("default", new GenericFormat());
        }
    }

    public void setClassMap(Map<String, String> classMap)
    {
        this.classMap = classMap;
    }

    public void setFormatMap(Map<String, JournalFormat> formatMap)
    {
        this.formatMap = formatMap;
    }

    public JournalAppender createAppender(JournalDesc desc)
    {
        List<AppenderDesc> appenderDescs = desc.getAppenderDescs();
        if (appenderDescs.size() > 1) {
            List<JournalAppender> appenders = new ArrayList<JournalAppender>();
            for (AppenderDesc appenderDesc : appenderDescs) {
                JournalAppender appender = createAppender(appenderDesc.getType(), desc);
                appenders.add(appender);
            }
            return new MultiAppender(desc, appenders.toArray(new JournalAppender[0]));
        }
        else {
            return createAppender(appenderDescs.get(0).getType(), desc);
        }
    }

    protected JournalAppender createAppender(String type, JournalDesc desc)
    {
        String className = classMap.get(type);
        AppenderDesc appenderDesc = desc.getAppenderDesc(type);
        JournalAppender appender = ReflectUtils.newInstance(className, new Object[]{desc, appenderDesc});
        if (appenderDesc != null) {
            String str = DataUtils.getString(appenderDesc.getProperty("format"), null);
            if (StringUtils.isNotBlank(str)) {
                JournalFormat format = formatMap.get(str);
                try {
                    MethodUtils.invokeMethod(appender, "setFormat", new Object[]{format});
                }
                catch (Throwable t) {
                    //do nothing
                }
            }
        }
        return appender;
    }
}
